"""
RAG系统日志模块:终端日志+详细文件日志
"""

import logging
import os
import json
from datetime import datetime
from typing import Dict, Any, List, Optional
from pathlib import Path
import hashlib

# 创建results目录
RESULTS_DIR = Path("./results")
RESULTS_DIR.mkdir(exist_ok=True)


class RAGLogger:
    """RAG系统日志记录器"""

    def __init__(self, query_id: str = None):
        """
        初始化日志记录器
        :param query_id: 查询唯一标识，如果为None则自动生成
        """
        self.query_id = query_id or self._generate_query_id()
        self.log_file = RESULTS_DIR / f"rag_process_{self.query_id}.log"
        self.json_file = RESULTS_DIR / f"rag_data_{self.query_id}.json"

        # 创建文件日志处理器
        self.file_logger = self._setup_file_logger()

        # 创建终端日志处理器
        self.console_logger = self._setup_console_logger()

        # 存储详细数据
        self.process_data = {
            "query_id": self.query_id,
            "timestamp": datetime.now().isoformat(),
            "steps": [],
        }

    def _generate_query_id(self) -> str:
        """生成唯一的查询ID"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
        return timestamp

    def _setup_file_logger(self) -> logging.Logger:
        """设置文件日志处理器"""
        logger = logging.getLogger(f"rag_file_{self.query_id}")
        logger.setLevel(logging.DEBUG)
        logger.handlers.clear()
        logger.propagate = False  # 关键：不传播到父logger，避免输出到终端

        # 文件处理器
        file_handler = logging.FileHandler(self.log_file, encoding="utf-8")
        file_handler.setLevel(logging.DEBUG)

        # 详细格式
        formatter = logging.Formatter(
            "%(asctime)s | %(levelname)-8s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
        )
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)

        return logger

    def _setup_console_logger(self) -> logging.Logger:
        """设置终端日志处理器"""
        logger = logging.getLogger(f"rag_console_{self.query_id}")
        logger.setLevel(logging.INFO)
        logger.handlers.clear()
        logger.propagate = False  # 关键：不传播到父logger

        # 终端处理器
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)

        # 简洁格式
        formatter = logging.Formatter("%(message)s")
        console_handler.setFormatter(formatter)
        logger.addHandler(console_handler)

        return logger

    def log_start(self, query: str, session_id: str, user_id: str):
        """记录查询开始"""
        separator = "=" * 80

        # 终端日志 - 极简
        self.console_logger.info(f"\n{'='*60}")
        self.console_logger.info(f"🚀 RAG检索开始")
        self.console_logger.info(
            f"📝 查询: {query[:50]}{'...' if len(query) > 50 else ''}"
        )

        # 文件日志 - 详细
        self.file_logger.info(separator)
        self.file_logger.info("RAG检索流程开始")
        self.file_logger.info(separator)
        self.file_logger.info(f"查询ID: {self.query_id}")
        self.file_logger.info(f"会话ID: {session_id}")
        self.file_logger.info(f"用户ID: {user_id}")
        self.file_logger.info(f"原始查询: {query}")
        self.file_logger.info(separator)

        # 保存数据
        self.process_data["query"] = query
        self.process_data["session_id"] = session_id
        self.process_data["user_id"] = user_id

    def log_query_type_detection(self, query_type: str, indicators: List[str] = None):
        """记录查询类型检测"""
        # 终端日志 - 只显示步骤名称
        self.console_logger.info(f"🔍 [1/6] 查询类型检测...")

        # 文件日志 - 详细信息
        self.file_logger.info("\n[步骤1] 查询类型检测")
        self.file_logger.info(f"检测结果: {query_type}")
        if indicators:
            self.file_logger.info(f"匹配指标: {', '.join(indicators)}")

        # 保存数据
        self.process_data["steps"].append(
            {
                "step": 1,
                "name": "查询类型检测",
                "query_type": query_type,
                "indicators": indicators,
            }
        )

    def log_query_rewrite(
        self, original_query: str, rewritten_queries: List[str], strategy: str
    ):
        """记录查询重写"""
        # 终端日志 - 只显示步骤，不显示数量
        self.console_logger.info(f"✍️  [2/6] 查询重写...")

        # 文件日志
        self.file_logger.info("\n[步骤2] 查询重写")
        self.file_logger.info(f"原始查询: {original_query}")
        self.file_logger.info(f"重写策略: {strategy}")
        self.file_logger.info(f"重写查询数量: {len(rewritten_queries)}")
        for i, query in enumerate(rewritten_queries, 1):
            self.file_logger.info(f"  重写查询{i}: {query}")

        # 保存数据
        self.process_data["steps"].append(
            {
                "step": 2,
                "name": "查询重写",
                "original_query": original_query,
                "strategy": strategy,
                "rewritten_queries": rewritten_queries,
            }
        )

    def log_hybrid_retrieval_start(self, query: str, top_k: int):
        """记录混合检索开始"""
        # 终端日志 - 只显示步骤，不显示参数
        self.console_logger.info(f"🔎 [3/6] 混合检索...")

        # 文件日志
        self.file_logger.info("\n[步骤3] 混合检索")
        self.file_logger.info(f"检索查询: {query}")
        self.file_logger.info(f"Top-K: {top_k}")

    def log_semantic_retrieval(self, results_count: int, top_scores: List[float]):
        """记录语义检索结果"""
        # 终端日志 - 不输出
        pass

        # 文件日志
        self.file_logger.info(f"  语义检索结果: {results_count}条")
        if top_scores:
            self.file_logger.info(
                f"  Top分数: {', '.join([f'{s:.4f}' for s in top_scores])}"
            )

        # 保存数据
        if not any(s["name"] == "混合检索" for s in self.process_data["steps"]):
            self.process_data["steps"].append(
                {
                    "step": 3,
                    "name": "混合检索",
                    "semantic": {"count": results_count, "top_scores": top_scores},
                }
            )
        else:
            for step in self.process_data["steps"]:
                if step["name"] == "混合检索":
                    step["semantic"] = {
                        "count": results_count,
                        "top_scores": top_scores,
                    }

    def log_bm25_retrieval(self, results_count: int, top_scores: List[float]):
        """记录BM25检索结果"""
        # 终端日志 - 不输出
        pass

        # 文件日志
        self.file_logger.info(f"  BM25检索结果: {results_count}条")
        if top_scores:
            self.file_logger.info(
                f"  Top分数: {', '.join([f'{s:.4f}' for s in top_scores])}"
            )

        # 保存数据
        for step in self.process_data["steps"]:
            if step["name"] == "混合检索":
                step["bm25"] = {"count": results_count, "top_scores": top_scores}

    def log_metadata_filter(self, results_count: int, metadata: Dict[str, Any]):
        """记录元数据过滤结果"""
        # 终端日志 - 不输出
        pass

        # 文件日志
        self.file_logger.info(f"  元数据过滤结果: {results_count}条")
        self.file_logger.info(
            f"  过滤元数据: {json.dumps(metadata, ensure_ascii=False, indent=2)}"
        )

        # 保存数据
        for step in self.process_data["steps"]:
            if step["name"] == "混合检索":
                step["metadata"] = {"count": results_count, "metadata": metadata}

    def log_merge_results(self, total_unique: int, weights: Dict[str, float]):
        """记录结果合并"""
        # 终端日志 - 不输出
        pass

        # 文件日志
        self.file_logger.info(f"  合并后唯一结果: {total_unique}条")
        self.file_logger.info(f"  权重配置: {json.dumps(weights, ensure_ascii=False)}")

        # 保存数据
        for step in self.process_data["steps"]:
            if step["name"] == "混合检索":
                step["merged"] = {"count": total_unique, "weights": weights}

    def log_reranking_start(self, results_count: int):
        """记录重排序开始"""
        # 终端日志 - 只显示步骤，不显示数量
        self.console_logger.info(f"📊 [4/6] 高级重排序...")

        # 文件日志
        self.file_logger.info("\n[步骤4] 高级重排序")
        self.file_logger.info(f"待重排序结果数: {results_count}")

    def log_reranking_scores(
        self,
        semantic_avg: float,
        keyword_avg: float,
        contextual_avg: float,
        weights: Dict[str, float],
    ):
        """记录重排序评分"""
        # 终端日志 - 不输出
        pass

        # 文件日志
        self.file_logger.info(
            f"  语义匹配平均分: {semantic_avg:.4f} (权重: {weights.get('semantic_matching', 0)})"
        )
        self.file_logger.info(
            f"  关键词覆盖平均分: {keyword_avg:.4f} (权重: {weights.get('keyword_coverage', 0)})"
        )
        self.file_logger.info(
            f"  上下文相关平均分: {contextual_avg:.4f} (权重: {weights.get('contextual_relevance', 0)})"
        )

        # 保存数据
        self.process_data["steps"].append(
            {
                "step": 4,
                "name": "高级重排序",
                "avg_scores": {
                    "semantic": semantic_avg,
                    "keyword": keyword_avg,
                    "contextual": contextual_avg,
                },
                "weights": weights,
            }
        )

    def log_reranking_results(self, top_results: List[Dict[str, Any]]):
        """记录重排序Top结果"""
        # 终端日志 - 不输出
        pass

        # 文件日志 - 详细记录Top结果
        self.file_logger.info("  Top重排序结果:")
        for i, result in enumerate(top_results[:5], 1):
            self.file_logger.info(f"    结果{i}:")
            self.file_logger.info(f"      综合分数: {result.get('final_score', 0):.4f}")
            self.file_logger.info(
                f"      语义分数: {result.get('semantic_score', 0):.4f}"
            )
            self.file_logger.info(
                f"      关键词分数: {result.get('keyword_coverage', 0):.4f}"
            )
            self.file_logger.info(
                f"      上下文分数: {result.get('contextual_relevance', 0):.4f}"
            )
            self.file_logger.info(
                f"      内容预览: {result.get('content', '')[:100]}..."
            )

        # 保存数据
        for step in self.process_data["steps"]:
            if step["name"] == "高级重排序":
                step["top_results"] = top_results[:10]  # 保存Top10

    def log_threshold_filter(
        self,
        before_count: int,
        after_count: int,
        base_threshold: float,
        adjusted_threshold: float,
    ):
        """记录动态阈值过滤"""
        # 终端日志 - 只显示步骤，不显示数据
        self.console_logger.info(f"🎯 [5/6] 动态阈值过滤...")

        # 文件日志
        self.file_logger.info("\n[步骤5] 动态阈值过滤")
        self.file_logger.info(f"基础阈值: {base_threshold:.4f}")
        self.file_logger.info(f"调整后阈值: {adjusted_threshold:.4f}")
        self.file_logger.info(f"过滤前结果数: {before_count}")
        self.file_logger.info(f"过滤后结果数: {after_count}")
        self.file_logger.info(f"过滤掉结果数: {before_count - after_count}")

        # 保存数据
        self.process_data["steps"].append(
            {
                "step": 5,
                "name": "动态阈值过滤",
                "before_count": before_count,
                "after_count": after_count,
                "base_threshold": base_threshold,
                "adjusted_threshold": adjusted_threshold,
            }
        )

    def log_final_results(
        self, results: List[Dict[str, Any]], retrieval_stats: Dict[str, Any]
    ):
        """记录最终结果"""
        # 终端日志 - 只显示步骤，不显示数量
        self.console_logger.info(f"✅ [6/6] 构建最终结果...")

        # 文件日志
        self.file_logger.info("\n[步骤6] 最终结果")
        self.file_logger.info(f"最终结果数: {len(results)}")
        self.file_logger.info(
            f"检索统计: {json.dumps(retrieval_stats, ensure_ascii=False, indent=2)}"
        )
        self.file_logger.info("\n最终结果详情:")
        for i, result in enumerate(results, 1):
            self.file_logger.info(f"  结果{i}:")
            self.file_logger.info(
                f"    综合分数: {result.get('final_score', result.get('score', 0)):.4f}"
            )
            self.file_logger.info(f"    内容: {result.get('content', '')[:200]}...")

        # 保存数据
        self.process_data["steps"].append(
            {
                "step": 6,
                "name": "最终结果",
                "final_count": len(results),
                "retrieval_stats": retrieval_stats,
                "results": results,
            }
        )

    def log_end(self, success: bool = True, error_msg: str = None):
        """记录查询结束"""
        separator = "=" * 80
        duration = (
            datetime.now() - datetime.fromisoformat(self.process_data["timestamp"])
        ).total_seconds()

        # 终端日志 - 极简
        if success:
            self.console_logger.info(f"{'='*60}")
            self.console_logger.info(
                f"✅ 完成 | 耗时: {duration:.2f}秒 | 日志: results/{self.log_file.name}"
            )
        else:
            self.console_logger.info(f"{'='*60}")
            self.console_logger.info(f"❌ 失败 | {error_msg}")
        self.console_logger.info(f"{'='*60}\n")

        # 文件日志
        self.file_logger.info(f"\n{separator}")
        self.file_logger.info(f"RAG检索流程{'成功' if success else '失败'}")
        self.file_logger.info(f"总耗时: {duration:.2f}秒")
        if error_msg:
            self.file_logger.info(f"错误信息: {error_msg}")
        self.file_logger.info(f"{separator}")

        # 保存完整数据为JSON
        self.process_data["success"] = success
        self.process_data["error"] = error_msg
        self.process_data["duration"] = duration

        with open(self.json_file, "w", encoding="utf-8") as f:
            json.dump(self.process_data, f, ensure_ascii=False, indent=2)

    def log_error(self, step: str, error: Exception):
        """记录错误"""
        # 终端日志 - 简洁
        self.console_logger.error(f"❌ [{step}] {str(error)[:80]}")

        # 文件日志 - 详细
        self.file_logger.error(f"[错误] {step}")
        self.file_logger.error(f"错误类型: {type(error).__name__}")
        self.file_logger.error(f"错误信息: {str(error)}")
        import traceback

        self.file_logger.error(f"堆栈跟踪:\n{traceback.format_exc()}")


def get_rag_logger(query: str = None) -> RAGLogger:
    """
    获取RAG日志记录器
    :param query: 查询文本，用于生成唯一ID
    :return: RAGLogger实例
    """
    if query:
        # 使用查询的哈希值作为部分ID
        query_hash = hashlib.md5(query.encode()).hexdigest()[:8]
        query_id = f"{datetime.now().strftime('%Y%m%d_%H%M%S')}_{query_hash}"
    else:
        query_id = None

    return RAGLogger(query_id)
